

/**
 * @file ComputeStaTides.cpp
 * This class computes station tides.
 */


#include "ComputeStaTides.hpp"

using namespace std;

namespace gpstk
{

    // Return a string identifying this object.
    std::string ComputeStaTides::getClassName() const
    { return "ComputeStaTides"; }



    Triple ComputeStaTides::getTides( const CommonTime& time,
                                      const string& station )
        noexcept(false)
    {

        try
        {
            Triple solidCorr, oceanCorr, poleCorr;

            solidCorr = solid.getSolidTide(time, nominalPos);
            if(correctOTL)
            {
                oceanCorr = ocean.getOceanLoading(time, station);
            }
            else
            {
                oceanCorr = Triple(0.0, 0.0, 0.0);
            }

            poleCorr = pole.getPoleTide(time, nominalPos);

            return solidCorr + oceanCorr + poleCorr;
        }
        catch(Exception& u)
        {
            // Throw an exception if something unexpected happens
            ProcessingException e( getClassName() + ":" + u.what() );
            GPSTK_THROW(e);
        }

    }  // End of method 'ComputeStaTides::Process()'

    /** Return a satTypeValueMap object, adding the new data generated when
     *  calling this object.
     *
     * @param time      Epoch corresponding to the data.
     * @param gData     Data object holding the data.
     */
    satTypeValueMap& ComputeStaTides::Process( const CommonTime& time,
                                              satTypeValueMap& gData )
        noexcept(false)
    {
        Triple tide;
        tide = getTides(time, station);
        sourceTideData[source] = tide;
    }


    void ComputeStaTides::Process(gnssRinex& gData)
        noexcept(false)
    {
        // solid
        solid.setReferenceSystem(*pRefSys);
        solid.setSolarSystem(*pSolSys);
        // ocean
        ocean.setBLQDataReader((*pBLQReader));
        ocean.setReferenceSystem(*pRefSys);
        // pole
        pole.setReferenceSystem(*pRefSys);

        // get receiver position from gnssDataHeader
        nominalPos = gData.header.srcPos;
        source = gData.header.source;
        station = source.sourceName;

        Process( gData.header.epoch, gData.body );

        gData.header.srcTide = sourceTideData[source];


    }  // End of method 'ComputeStaTides::Process()'


    /** Return a sourceRinex object, adding the new data generated
     *  when calling this object.
     *
     * @param gData    Data object holding the data.
     */
    void ComputeStaTides::Process(commonHeader& comHeader, gnssRinex& gData)
        noexcept(false)
    {
        pRefSys   = comHeader.pRefSys;
        pSolSys   = comHeader.pSolarSys;
        pBLQReader= comHeader.pBLQReader;
        pMSCStore = comHeader.pMSCStore;

        solid.setReferenceSystem(*pRefSys);
        solid.setSolarSystem(*pSolSys);

        ocean.setBLQDataReader((*pBLQReader));
        ocean.setReferenceSystem(*pRefSys);

        pole.setReferenceSystem(*pRefSys);

        // get receiver position from gnssDataHeader
        nominalPos = gData.header.srcPos;
        source = gData.header.source;
        station = source.sourceName;

        Process( gData.header.epoch, gData.body );

        gData.header.srcTide = sourceTideData[source];


    }  // End of method 'ComputeStaTides::Process()'

    /** Return a sourceRinex object, adding the new data generated
     *  when calling this object.
     *
     * @param gData    Data object holding the data.
     */
    void ComputeStaTides::Process(commonHeader& comHeader, sourceRinex& gData)
        noexcept(false)
    {
        pRefSys   = comHeader.pRefSys;
        pSolSys   = comHeader.pSolarSys;
        pBLQReader= comHeader.pBLQReader;
        pMSCStore = comHeader.pMSCStore;

        solid.setReferenceSystem(*pRefSys);
        solid.setSolarSystem(*pSolSys);

        ocean.setBLQDataReader((*pBLQReader));
        ocean.setReferenceSystem(*pRefSys);

        pole.setReferenceSystem(*pRefSys);

        SourceIDSet sourceRejectedSet;

        if(pMSCStore == NULL)
        {
            ProcessingException e("Pointer to ReferenceSystem NULL!");
            GPSTK_THROW(e);
        }

        CommonTime epoch( gData.header.epoch );
        epoch.setTimeSystem( TimeSystem::Unknown );

        for(sourceDataMap::iterator sdmIt = gData.body.begin();
            sdmIt != gData.body.end();
            ++sdmIt)
        {
            source = sdmIt->first;
            station = source.sourceName.substr(0,4);

            MSCData mscData;
            try
            {
                mscData = pMSCStore->findMSC(station,epoch);
            }
            catch(...)
            {
                sourceRejectedSet.insert( source );
                continue;
            }

            nominalPos = mscData.coordinates;

            Process( gData.header.epoch, sdmIt->second );

        }

        gData.removeSourceID( sourceRejectedSet );

        gData.header.srcTideData = sourceTideData;


    }  // End of method 'ComputeStaTides::Process()'


}  // End of namespace gpstk
